/*
 * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
 *
 * Author: Droiing <jianglinxuan@kylinos.cn>
 *         chenziyi <chenziyi@kylinos.cn>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <dlfcn.h>
#include<fcntl.h>
#include <unistd.h>
#include <libintl.h>
#include<sys/time.h>


#include <biometric_common.h>
#if 1			//20250224 //20250408
#include <biometric_stroge.h>
#else
#include <biometric_storage.h>
#endif
#include <biometric_version.h>
#include <biometric_config.h>



#include "common.h"
#include "app_fp256_360.h"
#include "ofp1234.h"
#include "usb_device.h"
#include "upgrade.h"

static int ENABLE_LOG_FILE = 0;	//通过配置文件使能logfile，0不输出日志到logfile，1输出日志
static int logfileFD = 0;

#define OFP2388_NAME	"ofp2388"
#define OFP2388_VERSION "V1.0.14"


static const struct usb_id ofp1234_id_table[] = {
	{ .idVendor = 0x1234, .idProduct = 0xABCD, .description = "OMS OFP1234"},
	{ .idVendor = 0x33A7, .idProduct = 0x2303, .description = "OMS OFP2303"},
	{ .idVendor = 0x33A7, .idProduct = 0x2388, .description = "OMS OFP2388"},
	{ 0, 0, NULL },
};

/*
* 开发者使用
* 设置录入进程阶段数
*
* @param[in] dev 设备结构体
* @param[in] type 进度类型
* @param[in] value 数据值
* @param[in] description 描述
*/
#if ENABLE_PROCESS_CHANGED
extern void bio_process_changed(bio_dev *dev, char *type, int value, char *description);
#endif

int ofp1234_onekey_powerup_identify(bio_dev *dev);
int ofp_get_current_user_fingerprint_num(bio_dev *dev, int uid);



int ofp_open_log_file(void)
{
	if(ENABLE_LOG_FILE)
	{
		if((logfileFD = open(OFP_LOG_FILE_NAME, O_RDWR|O_CREAT|O_APPEND, 0666))<0)
		{
			printf("%s open fail \n", OFP_LOG_FILE_NAME);
			logfileFD = 0;
			return -1;
		}
	}

	return 0;
}

int enable_printf_log(int flag)
{
	ENABLE_LOG_FILE = flag;
#if 0
	if(0 != ofp_open_log_file())
	{
		ENABLE_LOG_FILE = 0;
	}
#endif
	return 0;
}

//add by hcq, 20220331 12:00
int ofp_print_log(char *buf, int len)
{
	if(ENABLE_LOG_FILE)
	{
		if(0 != ofp_open_log_file())
		{
			return -1;
		}

		if((NULL == buf) || (0 == len))
		{
			D_ERR("the param is ERROR !!!\n");
			close(logfileFD);
			logfileFD = 0;
			return -1;
		}

		if((0 == logfileFD) || (-1 == logfileFD))
		{
			D_DBG("the logfileFD not open, ERROR !!!\n");
			logfileFD = 0;
			return -1;
		}

		write(logfileFD, buf, len);
		close(logfileFD);
		logfileFD = 0;
	}

	return 0;
}


//add by hcq, 20220331 12:00
int ofp_print_log_time(char *buf, int len)
{
	//D_DBG("start.\n");
	if(ENABLE_LOG_FILE)
	{
		if(0 != ofp_open_log_file())
		{
			return -1;
		}

		time_t current_time = time(NULL);//获取时间戳
		struct tm *local_time = localtime(&current_time);//将时间戳转换为本地时间
		char str[100] = {0};
		snprintf(str, 100, "%02d:%02d:%02d ", local_time->tm_hour, local_time->tm_min, local_time->tm_sec);

		if((NULL == buf) || (0 == len))
		{
			D_ERR("the param is ERROR !!!\n");
			close(logfileFD);
			logfileFD = 0;
			return -1;
		}

		if((0 == logfileFD) || (-1 == logfileFD))
		{
			D_DBG("the logfileFD not open, ERROR !!!\n");
			logfileFD = 0;
			return -1;
		}

		if(0 < strlen(str))
		{
			write(logfileFD, str, strlen(str));
		}

		write(logfileFD, buf, len);
		close(logfileFD);
		logfileFD = 0;
	}

	return 0;
}

//注册前判断当前指纹是否已录入 返回0表示已录入
int32 check_finger_is_enrolled(bio_dev *dev, int32 timeout_ms, int uid, int idx)
{
	int32 nRet = -1;
	feature_info *info_list = NULL;
	feature_info *info_list_head = NULL;
	uint16 identify_id = 0xffff;
	uint16 identify_result_id[ENROLL_NUM_MAX];
	uint16 identify_result_id_final = 0xffff;

	memset((char *)identify_result_id, 0xff, sizeof(identify_result_id));

	if(DRV_OK != fp_auto_identify(3, 0xffff, FP_CURRENT_OS_TYPE, identify_result_id, timeout_ms))
	{
		int32 flag = fp_get_ctrlFlag();
		WD_DBG("identify flag = %d\n", flag);
		switch(flag)
		{
			case FP_CONTROL_FLAG_STOPPED:
				fp_cancel();
				bio_set_ops_result (dev, OPS_COMM_STOP_BY_USER);
				bio_set_notify_mid (dev, NOTIFY_COMM_STOP_BY_USER);
				break;
			case FP_CONTROL_FLAG_TIMEOUT:
				fp_cancel();
				bio_set_ops_abs_result (dev, OPS_VERIFY_TIMEOUT);		   // 设置操作结果：验证超时
				bio_set_notify_abs_mid (dev, NOTIFY_VERIFY_TIMEOUT);
				break;
			case FP_CONTROL_FLAG_DEV_NOT_EXIST:
				bio_set_ops_result (dev, OPS_COMM_ERROR);							   //操作结果设置为：通用操作错误
				bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);					   //提示消息设置为：设备不可用
				break;
			default:
				fp_cancel();
				//bio_set_ops_abs_result (dev, OPS_VERIFY_ERROR); 	   // 设置操作结果：验证错误
				//bio_set_notify_abs_mid (dev, NOTIFY_VERIFY_ERROR);	   // 用户提醒消息：验证错误
				break;
		}
	}
	else
	{
		fp_cancel();//规避读取固件报文错位问题，

		// 连接数据库
		sqlite3 *db = bio_sto_connect_db ();
		// 从数据库中获取特征列表
		info_list = bio_sto_get_feature_info (db, -1, dev->bioinfo.biotype,dev->device_name, 0,-1);
		//info_list = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype, dev->device_name, idx, idx);
		info_list_head = info_list;
		// 打印特征列表
		//print_feature_info (info_list);
		// 断开数据库
		bio_sto_disconnect_db (db);

		WD_DBG("info_list=0x%x\r\n",info_list)
		while(NULL != info_list)
		{
			feature_sample *sample = info_list->sample;
			WD_DBG("sample=0x%x\r\n",sample)
			while(NULL != sample)
			{
				identify_id = sample->no;

				for(int n = 0; n < ENROLL_NUM_MAX; n++)
				{
					WD_DBG("n=%d,identify_result_id=%d,identify_id=%d,identify_result_id_final=%d\r\n", n,identify_result_id[n],identify_id,identify_result_id_final);
					if(0xffff == identify_result_id[n]){break;}

					if((identify_result_id[n] == identify_id) && (uid == info_list->uid)){
						identify_result_id_final = identify_result_id[n];
						WD_DBG("uid:%d identify_result_id_final=%d, identify_result_id=%d\r\n",uid, identify_result_id_final,identify_result_id[n]);
						break;
						}
				}
				if(0xffff != identify_result_id_final){break;}
				sample = sample->next;
				WD_DBG("identify_id=%d,identify_result_id_final=%d\r\n",identify_id,identify_result_id_final);
			}

			info_list = info_list->next;
		}
		bio_sto_free_feature_info_list (info_list_head);


		WD_DBG("identify_result_id_final = %d\r\n", identify_result_id_final);
		if(0xffff == identify_result_id_final)
		{
			nRet = -1;
		}
		else
		{
			nRet = 0;
		}
		WD_DBG("identify find nRet= %d\n", nRet);

	}
	return nRet;
}


int ofp1234_upgrade_pt(bio_dev *dev, int dev_exit_flag)
{
	int upgrade_ret = -1;

	WD_LOG("start.\n");
	if(0 != upgrade_module_init())
	{
		WD_ERR("upgrade_module_init failed!!!\n");
		return -1;
	}

	//int cycle_time = 0;
	//while(1)
	for(int i = 0; i < 10; i++)//未识别到设备，循环超过10秒则退出
	{
		if(DRV_OK == usb_dev_open(dev))//规避模组不能一次复位成功问题，add by hcq, 20230425
		{
			fp_reboot();
			usb_dev_close();
			dev->dev_num = 0;
			usleep(1000 * 1000);
		}

		if(0 < dev->dev_num)
		{
			return -1;
		}

		upgrade_ret = upgrade_and_run();
		if(0 == upgrade_ret)
		{
			WD_LOG("upgrade_and_run success.\n");
			usleep(1000 * 1000);
			return 0;
		}
		else if(-2 == upgrade_ret)
		{
			return -2;
		}


		if(0 == dev_exit_flag)//系统上电无设备时，应直接退出，避免卡住系统启动
		{
			break;
		}

		sleep(1);

		//cycle_time++;
		//if(10 < cycle_time)//未识别到设备，循环超过10秒则退出
		//{
		//	break;
		//}
	}

	return -1;
}


int ofp1234_upgrade_pt_notdelay(bio_dev *dev, int dev_exit_flag)
{
	int upgrade_ret = -1;

	D_LOG("start.\n");

    int ret = 0;

    ret = libusb_init(NULL);
    if(0 > ret)
    {
        WD_ERR("libusb_init failed.\n");
        return DRV_ERR;
    }

	//if(0 == upgrade_and_run())
	upgrade_ret = upgrade_and_run();
	if(0 == upgrade_ret)
	{
		D_LOG("upgrade_and_run success.\n");
		usleep(1000 * 1000);
		return 0;
	}
	else if(-2 == upgrade_ret)
	{
		return -2;
	}

	return DRV_ERR;
}


int32 ofp1234_check_firmware_version(bio_dev *dev)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	//int reboot_flag = priv->reboot_flag;
	//int err = 0;
	//pthread_t thr;

	WD_DBG("start, check_firmware_version\n");

	if((NULL == usb_get_dev_handle()) && (DRV_OK != usb_dev_open(dev)))
	{
		WD_DBG("can't open device!!!\n");
		return -1;
	}

	if((DRV_OK == fp_get_firmware_version()) && (0 < strlen(FIRMWARE_VERSION_NEW)))
	{
		//if(0 != strcmp(FIRMWARE_VERSION_NEW, fp_return_firmware_version()))
		if(((AUTO_UPGRADE == priv->config.upgrade_mode) && (0 != strcmp(FIRMWARE_VERSION_NEW, fp_return_firmware_version())))\
			|| ((SMART_UPGRADE == priv->config.upgrade_mode) && (FIRMWARE_VERSION_NUM_NEW > fp_return_firmware_version_num()))\
			|| (FORCE_UPGRADE == priv->config.upgrade_mode))

		{
			WD_LOG("current firmware version is %s, new firmware version is %s.\n", \
				fp_return_firmware_version(), FIRMWARE_VERSION_NEW);
			//if(FIRMWARE_VERSION_NUM_NEW > fp_return_firmware_version_num())
			if(1)
			{
				if(0 == check_file_exit())
				{
					fp_reboot();
					usb_dev_close();
					dev->dev_num = 0;
					usleep(1000 * 1000);
#if 1
					ofp1234_upgrade_pt(dev, 1);
#else
					err = pthread_create(&thr, NULL, (void *)ofp_upgrade_pt, NULL);
					if(err != 0) {
						WD_ERR(_("Can't create thread: %s\n"), strerror(err));
					}
#endif
				}
			}
			else
			{
				//rm_firmware_file();
				change_fw_upgrade_flag();
			}
		}
		else
		{
			WD_DBG("firmware don't need upgrade.\n");
#if 0
			FILE *file;

			file = fopen(UPGRADE_FILE, "rb");
			if(NULL != file)
			{
				fclose(file);
				char system_cmd[200] = "rm ";
				//strncat(system_cmd, UPGRADE_FILE, sizeof(UPGRADE_FILE));
				strncat(system_cmd, UPGRADE_FILE, 100);
				D_DBG("%s\n", system_cmd);
				system(system_cmd);

				char rm_oms_conf_cmd[200] = "rm ";
    			strncat(rm_oms_conf_cmd, FW_VERSION_FILE, 100);
				D_DBG("%s\n", rm_oms_conf_cmd);
    			system(rm_oms_conf_cmd);
			}
#else
			change_fw_upgrade_flag();
#endif
		}
	}

	usb_dev_close();

	return 0;
}



/*
 * 驱动初始化函数
*/
int ofp1234_ops_driver_init(bio_dev *dev)
{
	bio_print_debug ("ofp2388_ops_driver_init start.\n");

	// 私有结构体
	driver_info *priv = (driver_info *)dev->dev_priv;

	// 私有结构体超时时间成员变量设置初值为：框架通用的操作超时时间
	priv->timeoutMS = bio_get_ops_timeout_ms ();

	WD_DBG("priv->timeoutMS = %d\r\n", priv->timeoutMS);

	// 私有结构体控制标志成员变量设置初值为：CONTROL_FLAG_IDLE
	priv->ctrlFlag = CONTROL_FLAG_IDLE;

	//priv->cancellable = NULL;

	// 获取通用的context
	//set_fp_common_context (dev);

	usb_dev_get_port_path();

	if(0 < ofp1234_discover(dev))
	{
		ofp1234_onekey_powerup_identify(dev);//读取一键开机结果
		ofp1234_check_firmware_version(dev);
		ofp1234_set_mode(dev);
		ofp1234_set_reboot(dev);
	}
	else
	{
		//ofp1234_upgrade_pt(dev, 0);
		ofp1234_upgrade_pt_notdelay(dev, 0);
	}

	if(0 == usb_dev_get_port_path_valid_flag())
	{
		usb_dev_get_port_path();
	}

	if(0 == usb_dev_enable_autosuspend())
	{
		WD_DBG("usb_dev_enable_autosuspend.\r\n");
	}


	bio_print_debug ("bio_drv_demo_ops_driver_init end\n");

	return 0;
}

/*
 * 设备检测函数
*/
int ofp1234_ops_discover(bio_dev *dev)
{
	bio_print_debug ("bio_drv_demo_ops_discover start\n");

	int ret = 0;

	if(NULL != (dev->device_name))
		WD_DBG("%s start!\r\n", dev->device_name);

	// 探测设备
	ret = ofp1234_discover(dev);

	WD_DBG("bio_drv_demo_ops_discover ret = %d\n", ret);
	if ( ret < 0 ) {
		//DBG("[line%d]bio_drv_demo_ops_discover ret = %d\n", __LINE__, ret);
		//DBG("No %s fingerprint device detected\n", dev->device_name);
		WD_ERR("bio_drv_demo_ops_discover return -1\n");
		return -1;
	}
	if ( ret == 0 ) {
		//DBG("[line%d]bio_drv_demo_ops_discover ret = %d\n", __LINE__, ret);
		//DBG("No %s fingerprint device detected\n", dev->device_name);
		//DBG("[line%d]bio_drv_demo_ops_discover return 0\n", __LINE__);
		return 0;
	}

	bio_print_debug ("bio_drv_demo_ops_discover end\n");

	return ret;
}

/*
 * 设备打开函数
*/
int ofp1234_ops_open(bio_dev *dev)
{
	WD_DBG("bio_drv_demo_ops_open start\n");

	if(NULL != (dev->device_name))
		WD_DBG("%s start!\r\n", dev->device_name);

#if 0
	// 私有结构体
	driver_info *priv = (driver_info *)dev->dev_priv;
	priv->asyn_flag = ASYN_FALG_RUNNING;
	// 私有结构体控制变量成员设置为:CONTROL_FLAG_RUNNING
	priv->ctrlFlag = CONTROL_FLAG_RUNNING;
#endif
	if (dev->enable == false) {
		bio_set_dev_status (dev, DEVS_COMM_DISABLE);            //设备状态设置为：设备被禁用
		bio_set_ops_result (dev, OPS_COMM_ERROR);               //操作结果设置为：通用操作错误
		bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);      //提示消息设置为：设备不可用
		return -1;
	}

	bio_set_dev_status (dev, DEVS_OPEN_DOING);                        //设备状态设置为：正在打开设备

	fp_set_ctrlFlag(0);


#if 0
	// 创建一个GCancellable
	priv->cancellable = g_cancellable_new ();

	// 启动异步操作打开设备
	fp_device_open (priv->device, NULL, (GAsyncReadyCallback)on_device_opened, dev);
	while (1) {
		usleep (100);
		if (priv->asyn_flag == ASYN_FLAG_DONE) {
			break;
		} else {
			if (priv->timeused > priv->timeoutMS) {
				// 取消libfprint库异步操作
				g_cancellable_cancel (priv->cancellable);
					// 判断取消是否成功
					if (g_cancellable_is_cancelled (priv->cancellable)) {
						while (1) {
							usleep (100);
							if(priv->asyn_flag == ASYN_FLAG_DONE) {
								bio_set_ops_abs_result (dev, OPS_OPEN_FAIL);          // 设置操作结果：打开设备失败
								bio_set_notify_abs_mid (dev, NOTIFY_OPEN_FAIL);       // 用户提醒消息：打开设备失败
								bio_set_dev_status (dev, DEVS_COMM_IDLE);             // 设备状态：空闲状态
								return -1;
							}
						}
				}
			}
			priv->timeused += EM1600DEV_FINGER_CHECK_INTERVAL_MS;
			usleep (EM1600DEV_FINGER_CHECK_INTERVAL_MS * 1000);
		}
	}
#else
	if(DRV_OK != usb_dev_open(dev))
	{
		bio_set_ops_abs_result (dev, OPS_OPEN_FAIL);          // 设置操作结果：打开设备失败
		bio_set_notify_abs_mid (dev, NOTIFY_OPEN_FAIL);       // 用户提醒消息：打开设备失败
		bio_set_dev_status (dev, DEVS_COMM_IDLE);
		return -1;
	}

#endif
	// 设置状态
	bio_set_dev_status (dev, DEVS_COMM_IDLE);                    //当前状态设置为：空闲状态
	bio_set_ops_abs_result (dev, OPS_OPEN_SUCCESS);              //操作结果设置为：打开设备成功
	bio_set_notify_abs_mid (dev, NOTIFY_OPEN_SUCCESS);           //提示消息设置为：打开设备成功

	bio_print_debug ("bio_drv_demo_ops_open end\n");

	return 0;
}

/*
 * 设备关闭函数
*/
void ofp1234_ops_close(bio_dev *dev)
{
	bio_print_debug ("bio_drv_demo_ops_close start\n");

	if(NULL != (dev->device_name))
		WD_DBG("%s start!\r\n", dev->device_name);

	if (dev->enable == false) {
		bio_set_dev_status (dev, DEVS_COMM_DISABLE);                   //设备状态设置为：设备被禁用
		bio_set_ops_result (dev, OPS_COMM_ERROR);                      //操作结果设置为：通用操作错误
		bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);             //提示消息设置为：设备不可用
	}

	driver_info *priv = (driver_info *)dev->dev_priv;

	priv->ctrlFlag = CONTROL_FLAG_IDLE;
	usb_dev_close();

	bio_print_debug ("bio_drv_demo_ops_close end\n");

	return;
}

/*
 * 特征捕获函数，用来捕获生物特征信息
*/
char *ofp1234_ops_capture(bio_dev *dev, OpsActions action)
{
	bio_print_debug ("bio_drv_demo_ops_capture start\n");
#if 0
	capture_data *captureData = malloc(sizeof(capture_data));
	captureData->dev = dev;
	captureData->feature_data = NULL;
	captureData->feature_encode = NULL;
#endif
	//设备驱动不启用
	if (dev->enable == false) {
		bio_set_dev_status (dev, DEVS_COMM_DISABLE);              //设备状态设置为：设备被禁用
		bio_set_ops_result (dev, OPS_COMM_ERROR);                 //操作结果设置为：通用操作错误
		bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);        //提示消息设置为：设备不可用
		return NULL;
	}

	bio_set_dev_status (dev, DEVS_CAPTURE_DOING);                 //设备状态设置为：正在捕获信息
#if 0
	if (dev->bioinfo.eigtype == EigT_Data) {        // 原始数据

		captureData->feature_data = finger_capture (captureData);
		if (captureData->feature_data == NULL)
			return NULL;

		bio_set_dev_status (dev, DEVS_COMM_IDLE);                    //当前状态设置为：空闲状态
		bio_set_ops_result (dev, OPS_CAPTURE_SUCCESS);               //操作结果设置为：捕获成功
		bio_set_notify_abs_mid (dev, NOTIFY_CAPTURE_SUCCESS);        //提示消息设置为：捕获成功

		bio_print_debug ("bio_drv_demo_ops_capture end 1\n");
			return captureData->feature_data;

	} else if (dev->bioinfo.eigtype == EigT_Eigenvalue || dev->bioinfo.eigtype == EigT_Eigenvector) {   //特征值或者特征向量非纯字符串

		captureData->feature_data = finger_capture(captureData);
		if (captureData->feature_data == NULL)
			return NULL;

		// 64编码
		bio_base64_encode ((guchar *)captureData->feature_data, captureData->feature_encode, (sizeof(captureData->feature_encode)));

		bio_set_dev_status (dev, DEVS_COMM_IDLE);                      //当前状态设置为：空闲状态
		bio_set_ops_result (dev, OPS_CAPTURE_SUCCESS);                 //操作结果设置为：捕获成功
		bio_set_notify_abs_mid (dev, NOTIFY_CAPTURE_SUCCESS);          //提示消息设置为：捕获成功

		bio_print_debug ("bio_drv_demo_ops_capture end 2\n");
			return captureData->feature_encode;

	} else
#endif
	{
		bio_set_dev_status (dev, DEVS_COMM_IDLE);                      //当前状态设置为：空闲状态
		bio_set_ops_result (dev, OPS_CAPTURE_FAIL);                    //操作结果设置为：捕获失败
		bio_set_notify_abs_mid (dev, NOTIFY_CAPTURE_FAIL);             //提示消息设置为：捕获失败

		bio_print_debug ("bio_drv_demo_ops_capture end 3\n");
		return NULL;
	}
}



/*
 * 驱动释放函数
*/
void ofp1234_ops_free(bio_dev *dev)
{
	bio_print_debug ("bio_drv_demo_ops_free start\n");
#if 0
	driver_info *priv = (driver_info *)dev->dev_priv;

	key_t key;
	shared_number *share;
	// 申请一个key
	key = ftok ("/tmp/biometric_shared_file", 1234);

	priv->shmid = shmget (key, sizeof(shared_number), 0);
	priv->shmaddr = shmat (priv->shmid, NULL, 0);
	share = (shared_number *)(priv->shmaddr);

	share->d_count--;

	if (share->d_count == 0) {
		// 资源释放
		g_object_unref (priv->ctx);
		priv->devices = NULL;
		priv->device = NULL;
		// 解映射
		shmdt (priv->shmaddr);
		// 释放共享内存
		shmctl (priv->shmid, IPC_RMID, NULL);
	}
	// 关闭文件描述符
	close (priv->fd);
#endif
	bio_print_debug ("bio_drv_demo_ops_free end\n");
}

/*
 * 特征录入函数,用来录入用户的生物特征信息
*/
int ofp1234_ops_enroll(bio_dev *dev, OpsActions action, int uid, int idx, char *bio_idx_name)
{
	bio_print_debug ("bio_drv_demo_ops_enroll start\n");

	//设备驱动不启用
	if (dev->enable == false) {
		bio_set_dev_status (dev, DEVS_COMM_DISABLE);                           //设备状态设置为：设备被禁用
		bio_set_ops_result (dev, OPS_COMM_ERROR);                              //操作结果设置为：通用操作错误
		bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);                     //提示消息设置为：设备不可用
		return -1;
	}

	driver_info *priv = (driver_info *)dev->dev_priv;
	uint16 enroll_id = 0;
	int32 timeout_ms = priv->timeoutMS;

	// 用于获取可用索引
	if (idx == -1)
		idx = bio_common_get_empty_index (dev, uid, 0, -1);

	//每次录入操作超时时间不能大于框架通用超时时间
	if(bio_get_ops_timeout_ms() < timeout_ms)
		timeout_ms = bio_get_ops_timeout_ms();

	bio_set_dev_status (dev, DEVS_ENROLL_DOING);                           //设备状态设置为：正在录入

	WD_DBG("uid = %d, idx = %d, bio_idx_name = %s\r\n", uid, idx, bio_idx_name);
	fp_read_invalid_pkg(5);//规避读取固件报文错位问题，add by hcq, 20230607 13:30

	//if(-1 == idx_end)
	{
		D_DBG("ofp1234_ops_delete_invalid_feature.\r\n");
		ofp1234_ops_delete_invalid_feature(dev);
	}

	//应宝龙达姚海波需求，单账户录入指纹数量不超过10枚，add by hcq, 20230711
	if(10 <= ofp_get_current_user_fingerprint_num(dev, uid))
	{
		//此处待修改为设备存储已满, by hcq, 20230209

		snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("注册失败,指纹存储空间已满.\n"));// 用户提醒消息：指纹存储已满
		bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
		bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
		sleep(2);
		bio_set_ops_abs_result (dev, OPS_ENROLL_FAIL);          // 设置操作结果：录入失败
		bio_set_dev_status (dev, DEVS_COMM_IDLE);                  // 设备状态：空闲状态
		fp_cancel();//规避读取固件报文错位问题，add by hcq, 20230607 13:30
		return -1;
	}


while(1)
{
	int32 nEnrolled = check_finger_is_enrolled(dev, timeout_ms, uid, idx);
	if(0 == nEnrolled)
	{
		//snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("Current fingerprint already exist, please press your finger again.\n"));
		snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("按压的指纹与已有的指纹模版重复.\n"));
		bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
		bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
		WD_DBG("按压的指纹与已有的指纹模版重复.\n");
	}
	else
	{
		break;
	}
}

	enroll_id = fp_get_empty_enroll_id();
	WD_DBG("enroll_id = %d\r\n", enroll_id);

	if(FP_ENROLL_ID_MAX < enroll_id)
	{
		//此处待修改为设备存储已满, by hcq, 20230209

		snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("注册失败,指纹存储空间已满.\n"));// 用户提醒消息：指纹存储已满
		bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
		bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
		sleep(2);
		bio_set_ops_abs_result (dev, OPS_ENROLL_FAIL);          // 设置操作结果：录入失败
		bio_set_dev_status (dev, DEVS_COMM_IDLE);                  // 设备状态：空闲状态
		fp_cancel();//规避读取固件报文错位问题，add by hcq, 20230607 13:30
		return -1;
	}

	if(DRV_OK != fp_auto_enroll_start(enroll_id, 12, 0)) //20250224 6修改为12
	{
		switch(fp_get_ctrlFlag())
		{
			case FP_CONTROL_FLAG_ENROLLID_OUT_RANGE:
				snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("注册失败,指纹存储空间已满.\n"));// 用户提醒消息：指纹存储已满
				bio_set_ops_abs_result (dev, OPS_ENROLL_FAIL);			// 设置操作结果：录入失败
				bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
				bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
				sleep(2);
				break;
			default:
				bio_set_ops_abs_result (dev, OPS_ENROLL_FAIL);			// 设置操作结果：录入失败
				bio_set_notify_abs_mid (dev, NOTIFY_ENROLL_FAIL);		// 用户提醒消息：录入失败
				break;
		}
		fp_set_ctrlFlag(FP_CONTROL_FLAG_IDLE);
		if(CONTROL_FLAG_STOPING == priv->ctrlFlag)
		{
			priv->ctrlFlag = CONTROL_FLAG_STOPPED;
		}
		bio_set_dev_status (dev, DEVS_COMM_IDLE);                  // 设备状态：空闲状态
		fp_cancel();//规避读取固件报文错位问题，add by hcq, 20230607 13:30
		return -1;
	}

	snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("注册开始,请触摸指纹.\n"));
	bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
	bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));

	while(1)
	{
		if(DRV_OK != fp_auto_enroll(timeout_ms))
		{
			switch(fp_get_ctrlFlag())
			{
				case FP_CONTROL_FLAG_STOPPED:
					fp_cancel();
					bio_set_ops_result (dev, OPS_COMM_STOP_BY_USER);
					bio_set_notify_mid (dev, NOTIFY_COMM_STOP_BY_USER);
					break;
				case FP_CONTROL_FLAG_TIMEOUT:
					fp_cancel();
					bio_set_ops_abs_result (dev, OPS_ENROLL_TIMEOUT);          // 设置操作结果：录入超时
					bio_set_notify_abs_mid (dev, NOTIFY_ENROLL_TIMEOUT);
					break;
				case FP_CONTROL_FLAG_DEV_NOT_EXIST:
					bio_set_ops_result (dev, OPS_COMM_ERROR);                              //操作结果设置为：通用操作错误
					bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);                     //提示消息设置为：设备不可用
					break;
				default:
					fp_cancel();
					bio_set_ops_abs_result (dev, OPS_ENROLL_ERROR);		   // 设置操作结果：录入错误
					bio_set_notify_abs_mid (dev, NOTIFY_ENROLL_ERROR);	   // 用户提醒消息：录入错误
					break;
			}

			if(CONTROL_FLAG_STOPING == priv->ctrlFlag)
			{
				priv->ctrlFlag = CONTROL_FLAG_STOPPED;
			}

			fp_set_ctrlFlag(0);
			bio_set_dev_status (dev, DEVS_COMM_IDLE);				   // 设备状态：空闲状态
			return -1;
		}

		if(0 != fp_get_enroll_finish_flag())
		{
			break;
		}

		uint8 enroll_time = fp_get_current_enroll_time();
		if(0 < enroll_time)
		{
			uint8 create_feature_result = fp_get_enroll_create_feature_result(enroll_time);
			if(PROT_RESP_OK == create_feature_result)
			{
				switch(fp_get_enroll_result(enroll_time))
				{
					case  PROT_RESP_OK:	//录入成功
						snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("注册次数 %d/12.\n"), enroll_time); //20250224
						if(enroll_time == 6)
							snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("触摸手指边缘,注册次数 %d/12.\n"), enroll_time);//20250411
						bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
						bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
#if ENABLE_PROCESS_CHANGED
						bio_process_changed (dev, "enroll", (100 * enroll_time)/12, "enroll process");//20250224//录入进度展示，add by hcq, 20230419
#endif
						break;
					default:
						snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("注册失败,再触摸一次.\n"));
						bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
						bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
						break;
				}
			}
			else
			{
				switch(create_feature_result)
				{
					case PROT_RESP_OK:break;//生成特征成功
					case PROT_RESP_FPRINT_EXIST:	//指纹重复 按压的指纹与已有的指纹模版重复
						//snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("Current fingerprint already exist, please press your finger again.\n"));
						snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("按压的指纹与已有的指纹模版重复.\n"));
						bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
						bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
						WD_DBG("Current fingerprint already exist, please press your finger again.\n");
						break;
					case PROT_RESP_POSITION_REPEATED:	//位置重复
						//snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("Current fingerprint position repeated, please press your finger again.\n"));
						snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("按压的指纹与已有的指纹模版重复.\n"));
						bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
						bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
						WD_DBG("Current position repeated, please press your finger again.\n");
						break;
					case PROT_RESP_FPRINT_QUALITY_BAD:	//指纹质量不佳
						//snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("The quality of current fingerprint is bad, please press your finger again.\n"));
						snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("图像质量差,请再触摸指纹一次.\n"));
						bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
						bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
						WD_DBG("The quality of current fingerprint is bad, please press your finger again.\n");
						break;
					case PROT_RESP_FPRINT_AREA_TOO_SMALL:	//指纹面积过小
						//snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("The area of current fingerprint is too small, please press your finger again.\n"));
						snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("图像面积小,请再触摸指纹一次.\n"));
						bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
						bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
						WD_DBG("The area of current fingerprint is too small, please press your finger again.\n");
						break;
					default:
						//snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("Enroll failed, please press your finger again.\n"));
						snprintf (priv->extra_info, EXTRA_INFO_LENGTH, _("注册失败,请再触摸指纹一次.\n"));
						bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);
						bio_print_debug ("%s\n", bio_get_notify_mid_mesg(dev));
						WD_DBG("enroll_time%d result=0x%02x, error!!!\r\n", enroll_time, fp_get_enroll_result(enroll_time));
						break;
				}

			}
		}
	}
	fp_cancel();//规避读取固件报文错位问题，add by hcq, 20230607 13:30

	feature_info *info;
	char buf[1024] = {0};
	// 创建特征结构体
	info = bio_sto_new_feature_info (uid, dev->bioinfo.biotype, dev->device_name, idx, bio_idx_name);
	// 创建新的采样结构体
	info->sample = bio_sto_new_feature_sample (-1, NULL);
	info->sample->no = enroll_id;
	info->sample->data = buf;//bio_sto_new_str (feature_encode);
	// 打印特征结构体
	//print_feature_info (info);
	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();

	// 保存特征信息链表
	bio_sto_set_feature_info (db, info);

	// 断开数据库连接
	bio_sto_disconnect_db (db);

	// 回收特征数据项
	info->sample->data = NULL;

	bio_sto_free_feature_info_list (info);


	bio_print_debug ("bio_drv_demo_ops_enroll end\n");
	return 0;
}


/*
 * 特征验证函数,使用当前生物特征与指定特征对比,判断是否是同一个特征
*/
int ofp1234_ops_verify(bio_dev *dev, OpsActions action, int uid, int idx)
{
	bio_print_debug ("bio_drv_demo_ops_verify start\n");

	if (dev->enable == FALSE) {       // 设备不可用
		bio_set_dev_status(dev, DEVS_COMM_DISABLE);
		return -1;
	}

	driver_info *priv = (driver_info *)dev->dev_priv;
	int32 timeout_ms = priv->timeoutMS;

	//每次验证操作超时时间不能大于框架通用超时时间
	if(bio_get_ops_timeout_ms() < timeout_ms)
		timeout_ms = bio_get_ops_timeout_ms();

	bio_set_dev_status (dev, DEVS_VERIFY_DOING);         // 设备状态：正在验证
	fp_read_invalid_pkg(5);//规避读取固件报文错位问题，add by hcq, 20230607 13:30

#if 0
	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();
	// 从数据库中获取特征列表
	info_list = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype, dev->device_name, idx, idx);
	// 打印特征列表
	//print_feature_info (info_list);
	// 断开数据库
	bio_sto_disconnect_db (db);

	feature_sample *sample = info_list->sample;
	uint16 identify_id = 0xffff;
	uint16 identify_result_id[ENROLL_NUM_MAX];
	uint16 identify_result_id_final = 0xffff;

	memset((char *)identify_result_id, 0xff, sizeof(identify_result_id));
	while(NULL != sample)
	{
		identify_id = sample->no;
		DBG("%s:%d:%s: identify_id = %d\r\n", __FILE__, __LINE__, __func__, identify_id);

		//if(DRV_OK != fp_auto_identify(3, identify_id, 0, &identify_result_id, timeout_ms))
		if(DRV_OK != fp_auto_identify(3, 0xffff, FP_CURRENT_OS_TYPE, identify_result_id, timeout_ms))
		{
			switch(fp_get_ctrlFlag())
			{
				case FP_CONTROL_FLAG_STOPPED:
					fp_cancel();
					bio_set_ops_result (dev, OPS_COMM_STOP_BY_USER);
					bio_set_notify_mid (dev, NOTIFY_COMM_STOP_BY_USER);
					break;
				case FP_CONTROL_FLAG_TIMEOUT:
					fp_cancel();
					bio_set_ops_abs_result (dev, OPS_VERIFY_TIMEOUT);          // 设置操作结果：验证超时
					bio_set_notify_abs_mid (dev, NOTIFY_VERIFY_TIMEOUT);
					break;
				case FP_CONTROL_FLAG_DEV_NOT_EXIST:
					bio_set_ops_result (dev, OPS_COMM_ERROR);                              //操作结果设置为：通用操作错误
					bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);                     //提示消息设置为：设备不可用
					break;
				default:
					fp_cancel();
					bio_set_ops_abs_result (dev, OPS_VERIFY_ERROR);		   // 设置操作结果：验证错误
					bio_set_notify_abs_mid (dev, NOTIFY_VERIFY_ERROR);	   // 用户提醒消息：验证错误
					break;
			}
			fp_set_ctrlFlag(FP_CONTROL_FLAG_IDLE);

			if(CONTROL_FLAG_STOPING == priv->ctrlFlag)
			{
				priv->ctrlFlag = CONTROL_FLAG_STOPPED;
			}

			bio_set_dev_status (dev, DEVS_COMM_IDLE);                  // 设备状态：空闲状态
			bio_sto_free_feature_info_list (info_list);
			return -1;
		}
#if 0
		if((0xffff != identify_result_id) && (identify_result_id == identify_id))
		{
			DBG("%s:%d:%s: identify_id = %d, identify_result_id = %d\r\n", __FILE__, __LINE__, __func__, identify_id, identify_result_id);
			break;
		}
#else
		for(int n = 0; n < ENROLL_NUM_MAX; n++)
		{
			if(0xffff == identify_result_id[n])
			{
				break;
			}

			if(identify_result_id[n] == identify_id)
			{
				identify_result_id_final = identify_result_id[n];
				break;
			}
		}

		if(0xffff != identify_result_id_final)
		{
			break;
		}

#endif
		sample = sample->next;
	}
	bio_sto_free_feature_info_list (info_list);
#else
	feature_info *info_list = NULL;
	feature_info *info_list_head = NULL;
	uint16 identify_id = 0xffff;
	uint16 identify_result_id[ENROLL_NUM_MAX];
	uint16 identify_result_id_final = 0xffff;

	memset((char *)identify_result_id, 0xff, sizeof(identify_result_id));

	WD_DBG("idx = %d\n", idx);

	if(DRV_OK != fp_auto_identify(3, 0xffff, FP_CURRENT_OS_TYPE, identify_result_id, timeout_ms))
	{
		switch(fp_get_ctrlFlag())
		{
			case FP_CONTROL_FLAG_STOPPED:
				fp_cancel();
				bio_set_ops_result (dev, OPS_COMM_STOP_BY_USER);
				bio_set_notify_mid (dev, NOTIFY_COMM_STOP_BY_USER);
				break;
			case FP_CONTROL_FLAG_TIMEOUT:
				fp_cancel();
				bio_set_ops_abs_result (dev, OPS_VERIFY_TIMEOUT);		   // 设置操作结果：验证超时
				bio_set_notify_abs_mid (dev, NOTIFY_VERIFY_TIMEOUT);
				break;
			case FP_CONTROL_FLAG_DEV_NOT_EXIST:
				bio_set_ops_result (dev, OPS_COMM_ERROR);							   //操作结果设置为：通用操作错误
				bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);					   //提示消息设置为：设备不可用
				break;
			default:
				fp_cancel();
				bio_set_ops_abs_result (dev, OPS_VERIFY_ERROR); 	   // 设置操作结果：验证错误
				bio_set_notify_abs_mid (dev, NOTIFY_VERIFY_ERROR);	   // 用户提醒消息：验证错误
				break;
		}
		fp_set_ctrlFlag(FP_CONTROL_FLAG_IDLE);

		if(CONTROL_FLAG_STOPING == priv->ctrlFlag)
		{
			priv->ctrlFlag = CONTROL_FLAG_STOPPED;
		}

		WD_ERR("verify failed!!!\r\n");
		bio_set_dev_status (dev, DEVS_COMM_IDLE);				   // 设备状态：空闲状态
		return -1;
	}
	fp_cancel();//规避读取固件报文错位问题，add by hcq, 20230607 13:30

	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();
	// 从数据库中获取特征列表
	info_list = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype, dev->device_name, idx, idx);
	info_list_head = info_list;
	// 打印特征列表
	//print_feature_info (info_list);
	// 断开数据库
	bio_sto_disconnect_db (db);

	while(NULL != info_list)
	{
		feature_sample *sample = info_list->sample;
		while(NULL != sample)
		{
			identify_id = sample->no;

			for(int n = 0; n < ENROLL_NUM_MAX; n++)
			{
				if(0xffff == identify_result_id[n])
				{
					break;
				}

				if(identify_result_id[n] == identify_id)
				{
					identify_result_id_final = identify_result_id[n];
					break;
				}
			}

			if(0xffff != identify_result_id_final)
			{
				break;
			}

			sample = sample->next;
		}

		info_list = info_list->next;
	}
	bio_sto_free_feature_info_list (info_list_head);
#endif

	WD_DBG("identify_result_id_final = %d\r\n", identify_result_id_final);
	if(0xffff == identify_result_id_final)
	{
		bio_set_ops_abs_result (dev, OPS_VERIFY_NO_MATCH);
		bio_set_notify_abs_mid (dev, NOTIFY_VERIFY_NO_MATCH);
	}
	else
	{
		bio_set_ops_abs_result (dev, OPS_VERIFY_MATCH);
		bio_set_notify_abs_mid (dev, NOTIFY_VERIFY_MATCH);
	}
	bio_set_dev_status (dev, DEVS_COMM_IDLE);

	bio_print_debug ("bio_drv_demo_ops_verify end\n");
	return 0;
}

/*
 * 初始化过程中先发起identify获取一键开机结果，并保存15秒钟
*/
int ofp1234_onekey_powerup_identify(bio_dev *dev)
{
	WD_DBG("start.\n");

	if((NULL == usb_get_dev_handle()) && (DRV_OK != usb_dev_open(dev)))
	{
		WD_DBG("can't open device!!!\n");
		return -1;
	}

	init_onekey_powerup_search_id();
	fp_read_invalid_pkg(5);//规避取消报文错位，add by hcq, 20231020
	fp_onekey_powerup_identify(3, 0xffff, FP_CURRENT_OS_TYPE, get_onekey_powerup_search_id(), 20);
	fp_cancel();

	if(1 != get_onekey_powerup_flag())
	{
		set_onekey_powerup_flag(0);//若未读取到一键开机结果则设置为0
	}

	usb_dev_close();

	return DRV_OK;
}

/*
 * 特征识别函数,使用当前生物特征与指定范围的特征比对,识别出当前特征与指定范围内的哪个特征匹配
*/
int ofp1234_ops_identify(bio_dev *dev, OpsActions action, int uid, int idx_start, int idx_end)
{
	bio_print_debug ("bio_drv_demo_ops_identify start\n");

	// 设备不可用
	if (dev->enable == FALSE) {
		bio_set_dev_status(dev, DEVS_COMM_DISABLE);
		return -1;
	}

	int uid_ret = -1;
	driver_info *priv = (driver_info *)dev->dev_priv;

	WD_DBG("uid = %d, idx_start = %d, idx_end = %d\r\n", uid, idx_start, idx_end);
	bio_set_dev_status (dev, OPS_TYPE_IDENTIFY);                    // 设备状态设置为：正在识别指定特征
	//fp_read_invalid_pkg(5);//规避读取固件报文错位问题，add by hcq, 20230607 13:30 取消读空，避免睡眠后唤醒时无法读取到一键开机结果

	uint16 identify_result_id[ENROLL_NUM_MAX];
	//uint16 identify_result_id_final = 0xffff;

	memset((char *)identify_result_id, 0xff, sizeof(identify_result_id));

	//此处用于规避模组一键开机时，会将结果直接缓存在usb队列中，导致驱动初始化读取模组固件版本时，
	//先读到一键开机的结果，应答报文错位，流程混乱，后续应当由模组修改保证指令应答的准确性，add by hcq, 20230607
	if((1 == get_onekey_powerup_flag())&&(15*1000 > fp_get_increment_of_time_ms(get_onekey_powerup_tv_time())))
	{
		WD_LOG("received one key power up identify result.\n");
		//memcpy(identify_result_id, get_onekey_powerup_search_id(), get_onekey_powerup_search_num());
		for(int count = 0; count < get_onekey_powerup_search_num(); count++)
		{
			identify_result_id[count] = get_onekey_powerup_search_id()[count];
		}
		set_onekey_powerup_flag(0);
		WD_DBG("sleep 50ms\n");
		usleep(50 * 1000);
		goto OFP1234_OPS_IDENTIFY_DEAL_WITH_RESULT_ID;//若为一键开机结果，则直接跳转到处理结果
	}
	set_onekey_powerup_flag(0);

	//identify操作不设置超时时间，如锁屏时等待用户按下指纹，add by hcq, 20230214
	//if(DRV_OK != fp_auto_identify(3, 0xffff, 0, &identify_result_id, 0))
	if(DRV_OK != fp_auto_identify(3, 0xffff, FP_CURRENT_OS_TYPE, identify_result_id, 0))
	{
		switch(fp_get_ctrlFlag())
		{
			case FP_CONTROL_FLAG_STOPPED:
				fp_cancel();
				bio_set_ops_result (dev, OPS_COMM_STOP_BY_USER);
				bio_set_notify_mid (dev, NOTIFY_COMM_STOP_BY_USER);
				break;
			case FP_CONTROL_FLAG_TIMEOUT:
				fp_cancel();
				bio_set_ops_abs_result (dev, OPS_IDENTIFY_TIMEOUT);		   // 设置操作结果：识别超时
				bio_set_notify_abs_mid (dev, NOTIFY_IDENTIFY_TIMEOUT);
				break;
			case FP_CONTROL_FLAG_DEV_NOT_EXIST:
				bio_set_ops_result (dev, OPS_COMM_ERROR);							   //操作结果设置为：通用操作错误
				bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);					   //提示消息设置为：设备不可用
				break;
			default:
				fp_cancel();
				bio_set_ops_abs_result (dev, OPS_IDENTIFY_ERROR); 	   // 设置操作结果：识别错误
				bio_set_notify_abs_mid (dev, NOTIFY_IDENTIFY_ERROR);
				break;
		}
		fp_set_ctrlFlag(FP_CONTROL_FLAG_IDLE);

		if(CONTROL_FLAG_STOPING == priv->ctrlFlag)
		{
			priv->ctrlFlag = CONTROL_FLAG_STOPPED;
		}
		bio_set_dev_status (dev, DEVS_COMM_IDLE);
		WD_ERR("identify failed!!!\r\n");
		return -1;
	}

OFP1234_OPS_IDENTIFY_DEAL_WITH_RESULT_ID:


	if(0xffff == identify_result_id[0])
	{
		bio_set_ops_abs_result (dev, OPS_IDENTIFY_NO_MATCH);
		bio_set_notify_abs_mid (dev, NOTIFY_IDENTIFY_NO_MATCH);
		bio_set_dev_status (dev, DEVS_COMM_IDLE);
		WD_ERR("identify failed!!!\r\n");
		fp_cancel();
		return -1;
	}
	fp_cancel();

	feature_info *info_list = NULL;
	feature_info *info_list_head = NULL;
	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();
	// 获取特征列表
	info_list = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype, dev->device_name, idx_start, idx_end);
	info_list_head = info_list;
	// 打印特征列表
	print_feature_info (info_list);
	// 断开数据库
	bio_sto_disconnect_db (db);
	// 为匹配的特征构建新的特征链表，每个特征值对应一个采样特征值
	while (info_list != NULL)
	{
		feature_sample *sample = info_list->sample;
		while (sample != NULL)
		{
			//DBG("%s:%d:%s: uid = %d, sample->no = %d\r\n", __FILE__, __LINE__, __func__, info_list->uid, sample->no);
#if 0
			if(identify_result_id == sample->no)
			{
				uid_ret = info_list->uid;
				break;
			}
#else
			for(int n = 0; n < ENROLL_NUM_MAX; n++)
			{
				D_DBG("identify_result_id[%d] = 0x%04x\n", n, identify_result_id[n]);
				if(0xffff == identify_result_id[n])
				{
					break;
				}

				if(identify_result_id[n] == sample->no)
				{
					uid_ret = info_list->uid;
					break;
				}
			}

			if(-1 != uid_ret)
			{
				break;
			}
#endif
			sample = sample->next;
		}

		if(-1 != uid_ret)
		{
			break;
		}

		info_list = info_list->next;
	}
	// 回收特征数据项
	bio_sto_free_feature_info_list (info_list_head);

	bio_set_ops_abs_result (dev, OPS_IDENTIFY_MATCH);
	bio_set_notify_abs_mid (dev, NOTIFY_IDENTIFY_MATCH);
	bio_print_info ("%s\n", bio_get_notify_mid_mesg (dev));

	bio_set_dev_status (dev, DEVS_COMM_IDLE);

	WD_DBG("uid_ret = %d\r\n", uid_ret);
	bio_print_debug ("bio_drv_demo_ops_identify end\n");

	return uid_ret;
}

/*
 * 特征搜索函数,使用当前生物特征与指定范围的特征比对,搜索出指定范围内所有匹配的特征
*/
feature_info *ofp1234_ops_search(bio_dev *dev, OpsActions action, int uid, int idx_start, int idx_end)
{
	bio_print_debug ("bio_drv_demo_ops_search start\n");

	// 设备不可用
	if (dev->enable == FALSE) {
		bio_set_dev_status(dev, DEVS_COMM_DISABLE);
		return NULL;
	}

	driver_info *priv = (driver_info *)dev->dev_priv;
	int32 timeout_ms = priv->timeoutMS;

	//每次搜索操作超时时间不能大于框架通用超时时间
	if(bio_get_ops_timeout_ms() < timeout_ms)
		timeout_ms = bio_get_ops_timeout_ms();

	bio_set_dev_status (dev, OPS_TYPE_SEARCH);            // 设备状态设置为：正在搜索指定特征
	fp_read_invalid_pkg(5);//规避读取固件报文错位问题，add by hcq, 20230607 13:30

	uint16 identify_result_id[ENROLL_NUM_MAX];
	//uint16 identify_result_id_final = 0xffff;

	memset((char *)identify_result_id, 0xff, sizeof(identify_result_id));

	//if(DRV_OK != fp_auto_identify(3, 0xffff, 0, &identify_result_id, timeout_ms))
	if(DRV_OK != fp_auto_identify(3, 0xffff, FP_CURRENT_OS_TYPE, identify_result_id, timeout_ms))
	{
		switch(fp_get_ctrlFlag())
		{
			case FP_CONTROL_FLAG_STOPPED:
				fp_cancel();
				bio_set_ops_result (dev, OPS_COMM_STOP_BY_USER);
				bio_set_notify_mid (dev, NOTIFY_COMM_STOP_BY_USER);
				break;
			case FP_CONTROL_FLAG_TIMEOUT:
				fp_cancel();
				bio_set_ops_abs_result (dev, OPS_SEARCH_TIMEOUT);		   // 设置操作结果：搜索超时
				bio_set_notify_abs_mid (dev, NOTIFY_SEARCH_TIMEOUT);
				break;
			case FP_CONTROL_FLAG_DEV_NOT_EXIST:
				bio_set_ops_result (dev, OPS_COMM_ERROR);							   //操作结果设置为：通用操作错误
				bio_set_notify_abs_mid (dev, NOTIFY_COMM_DISABLE);					   //提示消息设置为：设备不可用
				break;
			default:
				fp_cancel();
				bio_set_ops_abs_result (dev, OPS_SEARCH_ERROR); 	   // 设置操作结果：验证错误
				bio_set_notify_abs_mid (dev, NOTIFY_SEARCH_ERROR);	   // 用户提醒消息：验证错误
				break;
		}
		fp_set_ctrlFlag(FP_CONTROL_FLAG_IDLE);

		if(CONTROL_FLAG_STOPING == priv->ctrlFlag)
		{
			priv->ctrlFlag = CONTROL_FLAG_STOPPED;
		}

		bio_set_dev_status (dev, DEVS_COMM_IDLE);
		return NULL;
	}

	if(0xffff == identify_result_id[0])
	{
		bio_set_ops_abs_result (dev, OPS_SEARCH_NO_MATCH);
		bio_set_notify_abs_mid (dev, NOTIFY_SEARCH_NO_MATCH);

		bio_set_dev_status (dev, DEVS_COMM_IDLE);
		fp_cancel();//规避读取固件报文错位问题，add by hcq, 20230607 13:30
		return NULL;
	}
	fp_cancel();//规避读取固件报文错位问题，add by hcq, 20230607 13:30

	feature_info *info_list = NULL;
	//int index = 0;
	feature_info *found = NULL;
	feature_info found_head;
	found_head.next = NULL;      // found_head的下一个特征信息指向空
	found = &(found_head);         // found指针指向found_head


	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();
	// 获取特征列表
	info_list = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype, dev->device_name, idx_start, idx_end);
	// 打印特征列表
	print_feature_info (info_list);
	// 断开数据库
	bio_sto_disconnect_db (db);
	// 为匹配的特征构建新的特征链表，每个特征值对应一个采样特征值
	while (info_list != NULL)
	{
		feature_sample *sample = info_list->sample;
		while (sample != NULL)
		{
			DBG("%s:%d:%s: uid = %d, sample->no = %d\r\n", __FILE__, __LINE__, __func__, info_list->uid, sample->no);
#if 0
			if(identify_result_id == sample->no)//搜索到对应特征
			{
				db = bio_sto_connect_db ();
				found = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype, dev->device_name, info_list->index, info_list->index);
				bio_sto_disconnect_db (db);
				break;
			}
#else
			for(int n = 0; n < ENROLL_NUM_MAX; n++)
			{
				if(0xffff == identify_result_id[n])
				{
					break;
				}

				if(identify_result_id[n] == sample->no)
				{
					WD_DBG("sample->no = %d\n", sample->no);
					db = bio_sto_connect_db ();
					found->next = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype, dev->device_name, info_list->index, info_list->index);
					found = found->next;
					bio_sto_disconnect_db (db);
					break;
				}
			}

#endif
			sample = sample->next;
		}
#if 0
		if(NULL != found)
		{
			break;
		}
#endif
		info_list = info_list->next;
	}
	// 回收特征数据项
	bio_sto_free_feature_info_list (info_list);

#if 0
	if(NULL == found_head.next)
	{
		found = NULL;
	}
#else
	found = found_head.next;
#endif

	if(NULL != found)
	{
		bio_set_ops_abs_result (dev, OPS_SEARCH_MATCH);
		bio_set_notify_abs_mid (dev, NOTIFY_SEARCH_MATCH);
	}
	else
	{
		bio_set_ops_abs_result (dev, OPS_SEARCH_NO_MATCH);
		bio_set_notify_abs_mid (dev, NOTIFY_SEARCH_NO_MATCH);
	}

	bio_set_dev_status (dev, DEVS_COMM_IDLE);

	bio_print_debug ("bio_drv_demo_ops_search end\n");

	return found;
}


/*
 * 特征清理(删除)函数,删除指定范围内的所有特征
*/
int ofp1234_ops_clean(bio_dev *dev, OpsActions action, int uid, int idx_start, int idx_end)
{
	bio_print_debug ("bio_drv_demo_ops_clean start\n");

	if (dev->enable == FALSE) {       // 设备不可用
		bio_set_dev_status(dev, DEVS_COMM_DISABLE);
		return 0;
	}

	bio_set_dev_status (dev, DEVS_CLEAN_DOING);       // 设备状态设置为：正在清理特征数据

	WD_DBG("idx_start = %d, idx_end = %d\r\n", idx_start, idx_end);

#if 0
	//if(-1 == idx_end)
	{
		DBG("%s:%d:%s: ofp1234_ops_delete_invalid_feature.\r\n", __FILE__, __LINE__, __func__);
		ofp1234_ops_delete_invalid_feature(dev);
	}
#endif

	feature_info *info_list = NULL;
	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();
	int ret = 0;

	// 获取特征列表
	info_list = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype, dev->device_name, idx_start, idx_end);
	// 打印特征列表
	print_feature_info (info_list);

	// 为匹配的特征构建新的特征链表，每个特征值对应一个采样特征值
	while (info_list != NULL)
	{
		feature_sample *sample = info_list->sample;
		uint16 enroll_id = 0xffff;
		while (sample != NULL)
		{
			WD_DBG("uid = %d, sample->no = %d\r\n", info_list->uid, sample->no);
			enroll_id = sample->no;
			ret = fp_delete_template(enroll_id, 1);
			if(0 != ret)
				break;
			sample = sample->next;
		}

		if(0 != ret)
			break;

		bio_sto_clean_feature_info (db, uid, dev->bioinfo.biotype,
								dev->device_name, info_list->index,
								info_list->index);

		info_list = info_list->next;
	}
	// 回收特征数据项
	bio_sto_free_feature_info_list (info_list);
	// 断开数据库
	bio_sto_disconnect_db (db);

	if (ret == 0) {
		bio_set_ops_abs_result (dev, OPS_CLEAN_SUCCESS);              // 操作结果设置为：清理特征成功
		bio_set_notify_abs_mid (dev, NOTIFY_CLEAN_SUCCESS);           // 用户提示设置为：清理特征成功
	} else {
		bio_set_ops_result (dev, OPS_CLEAN_FAIL);                     // 操作结果设置为：清理特征失败
		bio_set_notify_abs_mid (dev, NOTIFY_CLEAN_FAIL);              // 用户提示设置为：清理特征失败
	}

	bio_set_dev_status (dev, DEVS_COMM_IDLE);

	return ret;
}

/*
 * 删除无效指纹（模组中存在，数据库中不存在）
*/
int ofp1234_ops_delete_invalid_feature(bio_dev *dev)
{
	feature_info *found = NULL;

	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();
	uint8 index_table_info[INDEX_PAGE_NUM][32] = {{0}};
	// 从数据库中获取特征列表
	found = bio_sto_get_feature_info (db, -1, dev->bioinfo.biotype,
					dev->device_name, 0,
					-1);
	bio_sto_disconnect_db (db);// 断开数据库
	// 打印特征列表
	if(NULL != found)
	{
		print_feature_info (found);
		while(NULL != found)
		{
			feature_sample *sample = found->sample;

			while (sample != NULL)
			{
				uint16 sampleNo = 0xffff;

				//DBG("%s:%d:%s: uid = %d, sample->no = %d\r\n", __FILE__, __LINE__, __func__, found->uid, sample->no);
				sampleNo = sample->no;
				if(FP_ENROLL_ID_MAX >= sampleNo)
				{
					index_table_info[sampleNo/256][(sampleNo%256)/8] |= (0x01 << (sampleNo%8));
				}
				sample = sample->next;

			}
			found = found->next;
		}
	}
	bio_sto_free_feature_info_list (found);

	DBG("********========%s:%d:%s print index_table_info\r\n", __FILE__, __LINE__, __func__);
	for(int line = 0; line < INDEX_PAGE_NUM; line++)
	{
		for(int16 i = 0; i < 32; i++)
		{
			DBG("%02x ", index_table_info[line][i]);
		}
		DBG("\r\n");
	}
	fp_delete_invalid_template((uint8 *)index_table_info);

	return 0;
}

/*
 * 获取当前帐户已录入指纹数量
*/
int ofp_get_current_user_fingerprint_num(bio_dev *dev, int uid)
{
	feature_info *found = NULL;
	feature_info *found_head = NULL;
	int fingerprint_num = 0;

	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();
	//uint8 index_table_info[INDEX_PAGE_NUM][32] = {{0}};
	// 从数据库中获取特征列表
	found = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype,
					dev->device_name, 0,
					-1);
	found_head = found;
	bio_sto_disconnect_db (db);// 断开数据库
	// 打印特征列表
	if(NULL != found)
	{
		print_feature_info (found);
		while(NULL != found)
		{
			if(uid == found->uid)
			{
				fingerprint_num++;
			}

			found = found->next;
		}
	}
	bio_sto_free_feature_info_list (found_head);

	WD_LOG("current user uid %d, fingerprint_num = %d.\r\n", uid, fingerprint_num);

	return fingerprint_num;
}




/*
 * 获取指定设备的特征列表
*/
feature_info *ofp1234_ops_get_feature_list(bio_dev *dev, OpsActions action, int uid, int idx_start, int idx_end)
{
	bio_print_debug ("bio_drv_demo_ops_get_feature_list start\n");

	feature_info *found = NULL;
	//driver_info *priv = (driver_info *)dev->dev_priv;

	if (dev->enable == FALSE) {           // 设备不可用
		bio_set_dev_status(dev, DEVS_COMM_DISABLE);
		return NULL;
	}

	bio_set_dev_status (dev, OPS_TYPE_GET_FLIST);                        // 设备状态设置为：正在获取特征列表

	// 连接数据库
	sqlite3 *db = bio_sto_connect_db ();
	// 从数据库中获取特征列表
	found = bio_sto_get_feature_info (db, uid, dev->bioinfo.biotype,
					dev->device_name, idx_start,
					idx_end);
	// 打印特征列表
	print_feature_info (found);
	// 断开数据库
	bio_sto_disconnect_db (db);
	// 设置状态
	//snprintf (priv->extra_info, EXTRA_INFO_LENGTH, "_get_feature_list fingerprint template seccessful");
	bio_set_dev_status (dev, DEVS_COMM_IDLE);
	bio_set_ops_abs_result (dev, OPS_GET_FLIST_SUCCESS);
	//bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);

	bio_print_info ("%s\n", bio_get_notify_mid_mesg(dev));

	bio_set_dev_status (dev, DEVS_COMM_IDLE);

	return found;
}

/*
 * 中止设备的当前操作
*/
int ofp1234_ops_stop_by_user(bio_dev *dev, int waiting_ms)
{
	WD_DBG("start.\r\n");
	bio_print_debug ("bio_drv_demo_ops_stop_by_user start\n");

	bio_print_info (("_Device %s[%d] received interrupt request\n"), dev->device_name, dev->driver_id);

	if (bio_get_dev_status(dev) == DEVS_COMM_IDLE)    // 如果设备为空闲状态
		return 0;




	driver_info *priv = (driver_info *)dev->dev_priv;
	int timeout = 3 * 1000;//bio_get_ops_timeout_ms();          // 获取通用超时时间
	int timeused = 0;

	//priv->asyn_flag = ASYN_FALG_RUNNING;

	if (waiting_ms < timeout)
		timeout = waiting_ms;

	DBG("%s:%d:%s: timeout = %d.\r\n", __FILE__, __LINE__, __func__, timeout);

	// 设置状态位，用于通知用户中断
	priv->ctrlFlag = CONTROL_FLAG_STOPING;
	fp_set_ctrlFlag(FP_CONTROL_FLAG_STOPPED);

	//snprintf (priv->extra_info, EXTRA_INFO_LENGTH, ("_Device %s[%d] received interrupt request\n"), dev->device_name, dev->driver_id);
	//bio_set_notify_abs_mid (dev, MID_EXTENDED_MESSAGE);

	while ((priv->ctrlFlag != CONTROL_FLAG_STOPPED) &&
		(priv->ctrlFlag != CONTROL_FLAG_DONE) &&
		(priv->ctrlFlag != CONTROL_FLAG_IDLE) &&
		(timeused < timeout))
	{
		timeused += 10;//EM1600DEV_FINGER_CHECK_INTERVAL_MS;
		usleep(10 * 1000);//usleep(EM1600DEV_FINGER_CHECK_INTERVAL_MS * 1000);
	}

	if ((priv->ctrlFlag == CONTROL_FLAG_STOPPED)
	    || (priv->ctrlFlag == CONTROL_FLAG_DONE)
	    || (priv->ctrlFlag == CONTROL_FLAG_IDLE)) {
		return 0;
	}


	//return -1;
	WD_DBG("end.\r\n");
	return 0;

}


/*
 * 获取设备状态的文本消息
*/
const char *ofp1234_ops_get_dev_status_mesg(bio_dev *dev)
{
	bio_print_debug ("bio_drv_demo_ops_get_dev_status_mesg end\n");
	return NULL;
}

/*
 * 获取操作结果的文本消息
*/
const char *ofp1234_ops_get_ops_result_mesg(bio_dev *dev)
{
	bio_print_debug ("bio_drv_demo_ops_get_ops_result_mesg end\n");
	return NULL;
}

/*
 * 获取面向用户的提示消息
*/
const char *ofp1234_ops_get_notify_mid_mesg(bio_dev *dev)
{
	bio_print_debug ("bio_drv_demo_ops_get_notify_mid_mesg start\n");
#if 1
	driver_info *priv = (driver_info *)dev->dev_priv;

	switch (bio_get_notify_mid(dev))
	{
		case MID_EXTENDED_MESSAGE:
			return priv->extra_info;

		default:
			return NULL;
	}
#else
	return NULL;
#endif
}

void ofp1234_ops_attach(bio_dev *dev)
{
	WD_DBG("usb dev attach.\n");

	//WD_DBG("usb dev attach end.\n");
	//return NULL;
}

void ofp1234_ops_detach(bio_dev *dev)
{
	WD_DBG("usb dev detach.\n");
	usb_dev_set_port_path_valid_flag(0);
	WD_DBG("usb dev detach end.\n");
	//return NULL;
}

int ofp1234_para_config(bio_dev * dev, GKeyFile *conf)
{
	driver_info *priv = dev->dev_priv;
	int mode_flag = 0;
	int reboot_flag = 0;
	GError *err = NULL;
	int printf_log_flag = 0;

	D_DBG("start.\n");

	printf_log_flag = g_key_file_get_integer(conf, dev->device_name, PRINTF_LOG_FLAG, &err);
	if (err != NULL) {
		g_error_free(err);
		err = NULL;
		printf_log_flag = 0;
	}
	if(0 != printf_log_flag)
	{
		enable_printf_log(printf_log_flag);
		WD_LOG("%s = %d.\n", PRINTF_LOG_FLAG, printf_log_flag);
	}

	mode_flag = g_key_file_get_integer(conf, dev->device_name, "ModeFlag", &err);
	if (err != NULL) {
		g_error_free(err);
		err = NULL;
		mode_flag = 0;
	}
	priv->mode_flag = mode_flag;

	reboot_flag = g_key_file_get_integer(conf, dev->device_name, "RebootFlag", &err);
	if (err != NULL) {
		g_error_free(err);
		err = NULL;
		reboot_flag = 0;
	}
	priv->reboot_flag = reboot_flag;

	if((0 != mode_flag)||(0 != reboot_flag))\
	{
		gsize length;
		g_key_file_to_data(conf, &length, &err);
		if (err != NULL) {
			ERR(_("Error[%d]: %s\n"), err->code, err->message);
			g_error_free(err);
			err = NULL;
		}
		else
		{
			if(0 != mode_flag)
				g_key_file_set_integer(conf, dev->device_name, "ModeFlag", 0);

			if(0 != reboot_flag)
				g_key_file_set_integer(conf, dev->device_name, "RebootFlag", 0);

			g_key_file_save_to_file(conf, DRIVERS_CONFIG_FILE, &err);
			if (err != NULL) {
				ERR(_("Error[%d]: %s\n"), err->code, err->message);
				g_error_free(err);
				err = NULL;
			}
		}
	}

	D_DBG("end.\n");

	return 0;
}

int32 driver_config_init(DRIVER_CONFIG_STRUCT *config)
{
	GKeyFile *file = NULL;
	GError *err = NULL;
	int auto_suspend = 0;
	char *str_upgrade_mode = NULL;
	int printf_log_flag = 0;
	int upgrade_flag = 0;

	WD_DBG("start.\n");

	file = g_key_file_new();

	g_key_file_load_from_file(file, OFP_DRIVER_CONFIG_FILE, G_KEY_FILE_KEEP_TRANSLATIONS|G_KEY_FILE_KEEP_COMMENTS, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		g_key_file_free(file);
		return -1;
	}

	printf_log_flag = g_key_file_get_integer(file, BASIC_PARAM, PRINTF_LOG_FLAG, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		printf_log_flag = 0;
	}
	if(0 != printf_log_flag)
	{
		enable_printf_log(printf_log_flag);
		WD_LOG("================enable printf log================\n");
		WD_LOG("%s = %d.\n", PRINTF_LOG_FLAG, printf_log_flag);
	}

	auto_suspend = g_key_file_get_integer(file, BASIC_PARAM, AUTO_SUSPEND, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		auto_suspend = 0;
	}
	WD_DBG("set auto_suspend: %d\n", auto_suspend);
	config->autosuspend_flag = auto_suspend;
	usb_set_autosuspend_flag(config->autosuspend_flag);

	upgrade_flag = g_key_file_get_integer(file, BASIC_PARAM, STR_UPGRADE_FLAG, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		upgrade_flag = 0;
	}
	WD_DBG("set upgrade_flag: %d\n", upgrade_flag);
	config->upgrade_flag = upgrade_flag;

	str_upgrade_mode = g_key_file_get_string(file, BASIC_PARAM, UPGRADE_MODE, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		str_upgrade_mode = NULL;
	}

	if(NULL == str_upgrade_mode)
	{
		WD_DBG("set upgrade mode: %s\n", STR_AUTO_UPGRADE);
		config->upgrade_mode = AUTO_UPGRADE;
	}
	else if(0 == strcmp(STR_FORCE_UPGRADE, str_upgrade_mode))
	{
		WD_DBG("set upgrade mode: %s\n", STR_FORCE_UPGRADE);
		config->upgrade_mode = FORCE_UPGRADE;
	}
	else if(0 == strcmp(STR_DONT_UPGRADE, str_upgrade_mode))
	{
		WD_DBG("set upgrade mode: %s\n", STR_DONT_UPGRADE);
		config->upgrade_mode = DONT_UPGRADE;
	}
	else if(0 == strcmp(STR_AUTO_UPGRADE, str_upgrade_mode))
	{
		WD_DBG("set upgrade mode: %s\n", STR_AUTO_UPGRADE);
		config->upgrade_mode = AUTO_UPGRADE;
	}
	else if(0 == strcmp(STR_SMART_UPGRADE, str_upgrade_mode))
	{
		WD_DBG("set upgrade mode: %s\n", STR_SMART_UPGRADE);
		config->upgrade_mode = SMART_UPGRADE;
	}

	if(NULL != str_upgrade_mode)
	{
		g_free(str_upgrade_mode);
	}

	g_key_file_free(file);
	WD_DBG("end.\n");

	return 0;
}

int read_fw_upgrade_flag(void)
{
	GKeyFile *file = NULL;
	GError *err = NULL;
	int upgrade_flag = 0;
	int ret = -1;

	WD_DBG("start.\n");

	file = g_key_file_new();

	g_key_file_load_from_file(file, OFP_DRIVER_CONFIG_FILE, G_KEY_FILE_KEEP_TRANSLATIONS|G_KEY_FILE_KEEP_COMMENTS, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		g_key_file_free(file);
		return -1;
	}

	upgrade_flag = g_key_file_get_integer(file, BASIC_PARAM, STR_UPGRADE_FLAG, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		upgrade_flag = 0;
	}
	WD_DBG("upgrade_flag = %d\n", upgrade_flag);

	if(0 >= upgrade_flag)
	{
		ret = -1;
	}
	else
	{
		ret = 0;
	}

end:
	g_key_file_free(file);
	WD_DBG("end.\n");
	return ret;
}

int change_fw_upgrade_flag(void)
{
	GKeyFile *file = NULL;
	GError *err = NULL;
	int upgrade_flag = 0;
	int ret = -1;
	static uint8 upgrade_times = 0;

	WD_DBG("start.\n");

	if(0 < upgrade_times)
	{
		WD_DBG("upgrade_flag has been changed.\n");
		return 0;
	}

	file = g_key_file_new();

	g_key_file_load_from_file(file, OFP_DRIVER_CONFIG_FILE, G_KEY_FILE_KEEP_TRANSLATIONS|G_KEY_FILE_KEEP_COMMENTS, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		g_key_file_free(file);
		return -1;
	}

	upgrade_flag = g_key_file_get_integer(file, BASIC_PARAM, STR_UPGRADE_FLAG, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		upgrade_flag = 0;
		goto end;
	}
	WD_DBG("upgrade_flag = %d\n", upgrade_flag);
	if(0 >= upgrade_flag)
	{
		ret = 0;
		goto end;
	}

	upgrade_flag--;

	gsize length;
	g_key_file_to_data(file, &length, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		goto end;
	}
	else
	{
		g_key_file_set_integer(file, BASIC_PARAM, STR_UPGRADE_FLAG, upgrade_flag);
		g_key_file_save_to_file(file, OFP_DRIVER_CONFIG_FILE, &err);
		if (err != NULL) {
			WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
			g_error_free(err);
			err = NULL;
			goto end;
		}
	}

	ret = 0;
	upgrade_times++;
	WD_DBG("change upgrade_flag = %d\n", upgrade_flag);

end:
	g_key_file_free(file);
	WD_DBG("end.\n");
	return ret;
}



int ops_configure(bio_dev * dev, GKeyFile * conf)
{
	WD_DBG("start ******************=========\r\n");
	dev->driver_id = bio_get_empty_driver_id();
	dev->device_name = OFP2388_NAME;
	dev->full_name = "OMS OFP2388";
	dev->bioinfo.biotype = BioT_FingerPrint;
	//dev->bioinfo.stotype = StoT_OS;
	//dev->bioinfo.stotype = StoT_Mix;//混合存储
	dev->bioinfo.stotype = StoT_Device;//存储在硬件中
	dev->bioinfo.eigtype = EigT_Eigenvalue;
	//dev->bioinfo.vertype = VerT_Software;
	//dev->bioinfo.vertype = VerT_Mix;//混合验证
	dev->bioinfo.vertype = VerT_Hardware;//硬件验证
	//dev->bioinfo.idtype = IdT_Software;
	//dev->bioinfo.idtype = IdT_Mix;//混合识别
	dev->bioinfo.idtype = IdT_Hardware;//硬件识别
	dev->bioinfo.bustype = BusT_USB;

	dev->usb_info.id_table = ofp1234_id_table;
	dev->usb_info.driver_data = 0;

	dev->ops_configure = ops_configure;
	dev->ops_driver_init = ofp1234_ops_driver_init;
	dev->ops_discover = ofp1234_ops_discover;
	dev->ops_open = ofp1234_ops_open;
	dev->ops_enroll = ofp1234_ops_enroll;
	dev->ops_verify = ofp1234_ops_verify;
	dev->ops_identify = ofp1234_ops_identify;
	dev->ops_capture = ofp1234_ops_capture;
	dev->ops_search = ofp1234_ops_search;
	dev->ops_clean = ofp1234_ops_clean;
	dev->ops_get_feature_list = ofp1234_ops_get_feature_list;
	dev->ops_attach = ofp1234_ops_attach;
	dev->ops_detach = ofp1234_ops_detach;
	dev->ops_stop_by_user = ofp1234_ops_stop_by_user;
	dev->ops_feature_rename = NULL;	// Use the default function provided by the framework
	dev->ops_close = ofp1234_ops_close;
	dev->ops_free = ofp1234_ops_free;

	dev->ops_get_ops_result_mesg = ofp1234_ops_get_ops_result_mesg;//community_ops_get_ops_result_mesg;
	dev->ops_get_dev_status_mesg = ofp1234_ops_get_dev_status_mesg;//community_ops_get_dev_status_mesg;
	dev->ops_get_notify_mid_mesg = ofp1234_ops_get_notify_mid_mesg;//community_ops_get_notify_mid_mesg;

	bio_set_drv_api_version(dev);
	bio_set_dev_status(dev, DEVS_COMM_IDLE);
	bio_set_ops_result(dev, OPS_COMM_SUCCESS);
	bio_set_notify_mid(dev, NOTIFY_COMM_IDLE);

	dev->enable = bio_dev_is_enable(dev, conf);
#if 1
	driver_info *priv = g_new0 (driver_info, 1);
	dev->dev_priv = priv;

	//priv->community_driver_id = OFP2388_NAME;
	fp_module_init();
	usb_dev_module_init();

	driver_config_init(&(priv->config));
	ofp1234_para_config(dev, conf);
	WD_LOG("ofp2388 driver version:%s\n", OFP2388_VERSION);
	read_fw_version();
#endif
	WD_DBG("end ******************=========\r\n");

	return 0;
}

